package com.kabigon.mall.multi.config.intercecpter;

import cn.hutool.json.JSONUtil;
import com.kabigon.mall.multi.common.api.JsonResult;
import com.kabigon.mall.multi.common.api.ResultCode;
import com.kabigon.mall.multi.common.service.RedisService;
import com.kabigon.mall.multi.util.IpAdrressUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author xu.biao
 * @version v1.0
 * @Package com.kabigon.mall.multi.config
 * @data 2022/6/5 22:34
 */
@Slf4j
public class IpUrlLimitIntercepter implements HandlerInterceptor {

    /**
     * 锁ip地址
     */
    private static final String LOCK_IP_URL_KEY = "lock_ip_";

    /**
     * ip url请求时间
     */
    private static final String IP_URL_REQ_TIME = "ip_url_times_";


    /**
     * 限制时间
     */
    private static final long LIMIT_TIMES = 5;

    /**
     * ip锁定时间
     */
    private static final int IP_LOCK_TIME = 60;

    @Autowired
    private RedisService redisService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("request请求地址uri={},ip={}", request.getRequestURI(), IpAdrressUtil.getRequestIp(request));
        if (Boolean.TRUE.equals(ipIsLock(IpAdrressUtil.getRequestIp(request)))) {
            log.info("ip访问被禁止={}", IpAdrressUtil.getRequestIp(request));
            JsonResult result = JsonResult.failed(ResultCode.LOCK_IP);
            returnJson(response, JSONUtil.toJsonStr(result));
            return false;
        }
        if (Boolean.FALSE.equals(addRequestTime(IpAdrressUtil.getRequestIp(request), request.getRequestURI()))) {
            JsonResult result = JsonResult.failed(ResultCode.LOCK_IP);
            returnJson(response, JSONUtil.toJsonStr(result));
            return false;
        }
        return true;
    }

    /**
     * 判断ip是否被禁用
     *
     * @return {@link Boolean}
     */
    private Boolean ipIsLock(String ip) {
        return Boolean.TRUE.equals(redisService.hasKey(LOCK_IP_URL_KEY + ip));
    }

    /**
     * 记录请求次数
     *
     * @param ip
     * @param uri
     * @return {@link Boolean}
     */
    private Boolean addRequestTime(String ip, String uri) {
        String key = IP_URL_REQ_TIME + ip + uri;
        if (Boolean.TRUE.equals(redisService.hasKey(key))) {
            long time = redisService.incr(key, 1L);
            if (time >= LIMIT_TIMES) {
                redisService.getLock(LOCK_IP_URL_KEY + ip, ip, IP_LOCK_TIME);
                return false;
            }
        } else {
            redisService.getLock(key, 1L, 1);
        }
        return true;
    }

    private void returnJson(HttpServletResponse response, String json) throws Exception {
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/json; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.print(json);
        } catch (IOException e) {
            log.error("LoginInterceptor response error ---> {}", e.getMessage(), e);
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

}
